import Taro, {getCurrentInstance, requestPayment} from "@tarojs/taro";
import {Toast} from "@antmjs/vantui";


import JsonUtils from "@/utils/json_utils";
import {MoreOptions, PayParamsModel} from "@/common/apis/model";
import LogUtils from "@/utils/log";
import LocalUtils from "@/utils/local_utils";
import LocalData from "@/common/local_data";
import RouthPath from "@/common/RouthPath";
import {DynamicFormData} from "@/common/types";
import {FormConfig} from "@/components/DynamicForm";

interface ModalCallback {
  (confirmed: boolean): void;
}


type EventActionCallback = (data: any) => void; // 你可以将 any 替换为更具体的 data 类型
export default class Utils {
  static getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min)) + min; // The maximum is exclusive and the minimum is inclusive
  }

  static delay(sec: number) {
    return new Promise(resolve => setTimeout(resolve, sec * 1000));
  }

  static isHttpUrl(url: string | null | undefined): boolean {
    // 1. Guard against null/undefined or non-string inputs
    if (!url) {
      return false;
    }

    const trimmedUrl = url.trim();
    return trimmedUrl.startsWith('http://') || trimmedUrl.startsWith('https://');
  }

  static formatISODateToLocal(isoDateString: string, options?: Intl.DateTimeFormatOptions) {
    const date = new Date(isoDateString);
    return date.toLocaleString();
  }

  static showToast(params) {
    Taro.showToast(params).then(r => {
    });
  }

  static showErrorToast(title: string) {
    Taro.showToast({
      title: title,
      icon: 'none',
    }).then(r => {
    });
  }

  static stopRefresh() {
    Taro.stopPullDownRefresh()
  }

  static copyToClipboard() {
    this.copyToClipboardText(LocalData.acceptAddress)
  }

  static copyToClipboardText(text: string) {
    Taro.setClipboardData({
      data: text,
      success: () => {
        Utils.showOkToast('复制成功');
      }
    });
  }

  static navigateAndListenToEvent(url: string,
                                  eventName: string, // 允许指定事件名称，使其更通用
                                  onEventAction: EventActionCallback): void {
    Taro.navigateTo({
      url: url,
      success: (res) => {
        if (res.eventChannel) {
          res.eventChannel.on(eventName, (data) => {
            onEventAction(data);
          });
          // 你也可以在这里添加 res.eventChannel.emit() 来向目标页面发送初始数据，如果需要的话
        } else {
        }
      },
      fail: (err) => {
        // 在这里可以添加错误处理逻辑，例如显示一个提示
        Taro.showToast({
          title: '页面跳转失败',
          icon: 'none',
          duration: 2000
        });
      }
    });
  }

  static showOkToast(title: string, duration: number = 1500) {
    Taro.showToast({
      title: title,
      duration: duration
    }).then(r => {
    });
  }


  static testJson(a) {
    const d = {}
    d["1"] = "1"
    d["b"] = "2"
    d[a] = "6"
    console.log(d)
  }

  /**
   * 处理数据，将对象或对象数组中所有以 "question_" 开头的键（key）去掉该前缀。
   *
   * @param {Object | Object[]} data - 需要处理的单个对象或对象数组。
   * @returns {Object | Object[]} - 返回处理后的新对象或新数组，原始数据不会被修改。
   */
  static processKeys(data) {
    // 假设 LocalData.FIlED_START 是一个常量，例如 'question_'
    const FIlED_START = 'question_'; // 模拟 LocalData.FIlED_START

    const transformObject = (obj) => {
      // 检查输入是否为有效的对象
      if (obj === null || typeof obj !== 'object' || Array.isArray(obj)) {
        return obj; // 如果不是对象，直接返回原值
      }

      const newObj = {}; // 创建一个新对象，避免修改原始对象

      // 遍历原始对象的每一个 [键, 值] 对
      for (const [key, value] of Object.entries(obj)) {
        // --- 第一步：转换 key (保持不变) ---
        let newKey = key; // 默认新键等于旧键
        if (key.startsWith(FIlED_START)) {
          newKey = key.replace(FIlED_START, '');
        }

        // --- 第二步：转换 value (新增逻辑) ---
        let processedValue = value; // 默认使用原始值

        // 检查 value 是否为数组
        if (Array.isArray(value)) {
          // 如果是数组，使用 join(',') 方法将其转换为逗号分隔的字符串
          processedValue = value.join(',');
        }

        // 在新对象中设置处理后的键和处理后的值
        newObj[newKey] = processedValue;
      }

      return newObj; // 返回改造后的新对象
    };

    // 判断输入是数组还是单个对象 (保持不变)
    if (Array.isArray(data)) {
      // 如果是数组，使用 map 方法对数组中的每个对象应用转换函数
      return data.map(transformObject);
    } else {
      // 如果是单个对象，直接调用转换函数
      return transformObject(data);
    }
  }

  /**
   * 还原数据，将对象或对象数组中所有键（key）添加 "question_" 前缀，
   * 并将以逗号分隔的字符串值转换回数组。
   *
   * 这是 processKeys 方法的逆向操作。
   *
   * @param {Object | Object[]} data - 需要处理的单个对象或对象数组。
   * @returns {Object | Object[]} - 返回处理后的新对象或新数组，原始数据不会被修改。
   */
  static restoreKeys(data) {
    // 假设 LocalData.FIlED_START 是一个常量，例如 'question_'
    const FIlED_START = 'question_'; // 与原方法保持一致

    const transformObject = (obj) => {
      // 检查输入是否为有效的对象
      if (obj === null || typeof obj !== 'object' || Array.isArray(obj)) {
        return obj; // 如果不是对象，直接返回原值
      }

      const newObj = {}; // 创建一个新对象，避免修改原始对象

      // 遍历原始对象的每一个 [键, 值] 对
      for (const [key, value] of Object.entries(obj)) {
        // --- 第一步：转换 key (添加前缀) ---
        // 为每一个键都添加前缀
        const newKey = FIlED_START + key;

        // --- 第二步：转换 value (逆向操作，将字符串转回数组) ---
        let processedValue = value; // 默认使用原始值

        // 检查 value 是否为字符串，并且包含逗号
        // 这是对 `value.join(',')` 最直接的逆向猜测
        if (typeof value === 'string' && value.includes(',')) {
          // 如果是，使用 split(',') 方法将其转换回数组
          processedValue = value.split(',');
        } else if (typeof value === 'string' && value === '') {
          // 特殊处理：如果原数组是空的 `[]`，join(',') 后会变成空字符串 `''`
          // 在逆向时，将空字符串转回空数组是一种常见的需求。
          // 如果您不希望这样，可以移除这个 else if 分支。
          processedValue = [];
        }


        // 在新对象中设置处理后的键和处理后的值
        newObj[newKey] = processedValue;
      }

      return newObj; // 返回改造后的新对象
    };

    // 判断输入是数组还是单个对象 (逻辑与原方法相同)
    if (Array.isArray(data)) {
      // 如果是数组，使用 map 方法对数组中的每个对象应用转换函数
      return data.map(transformObject);
    } else {
      // 如果是单个对象，直接调用转换函数
      return transformObject(data);
    }
  }

  //EventUtils.trigger(EventUtils.RefreshOrder, true);
  //       EventUtils.trigger(EventUtils.UserInfo, true);
  static showToastAndNavigate(
    title = '操作成功',
    delta = 1,
    delay = 1500,
    callback?: () => void // <--- 新增一个可选的回调函数参数
  ) {
    Taro.showToast({
      title,
      icon: 'success',
      duration: delay,
      mask: true // 建议加上 mask
    });

    setTimeout(() => {
      // 在导航前，检查并执行回调函数
      if (callback && typeof callback === 'function') {
        callback();
      }

      // 然后再执行导航
      Taro.navigateBack({delta});
    }, delay);
  }

  static navigateTo(params) {
    Taro.navigateTo(params).then(r => {
    });
  }

  static makePhoneCall(phoneNumber) {
    Taro.makePhoneCall({
      phoneNumber: phoneNumber,
      success: () => {
        console.log('拨打电话成功')
      },
      fail: (err) => {
        console.error('拨打电话失败', err)
      }
    })
  }


  static showShareImageMenu(params) {
    Taro.showShareImageMenu(params).then(r => {
    });
  }

  static reLaunch(params, num = 0) {
    //判断params中的url不能为空
    LogUtils.info(`params=${params.url}=${num}`)
    if (!params.url) {
      return;
    }
    Taro.reLaunch(params).then(r => {
    });
  }

  static setTitle(title) {
    Taro.setNavigationBarTitle({
      title: title
    }).then(r => {
    });
  }

//
  static navigateBack(params?) {
    params = params || {
      delta: 1
    };
    Taro.navigateBack(params).then(r => {
    });
  }

  static navigateToThen(params) {
    return Taro.navigateTo(params);
  }

  static redirectTo(params) {
    Taro.redirectTo(params).then(r => {
    });
  }

  static switchTab(params) {
    Taro.switchTab(params).then(r => {
    });
  }


  static isWeapp() {
    return Taro.getEnv() === Taro.ENV_TYPE.WEAPP;
  }

  static addAccessToken(params) {
    return {...params, accessToken: '1111'};
  }

  static isNotBlank(value) {
    if (typeof value === 'string') {
      return value.trim() !== '';
    }
    return !(value === null || value === undefined);
  }

  static showLoading(title: string = '请稍候...', mask: boolean = true): void {
    Taro.showLoading({
      mask: mask,
      title: title
    }).then(r => {
    });
  }

  static clear(): void {
    Toast.clear()
  }

  static toast(text: string = "出错啦~", duration: number = 2000, success: boolean = false): void {
    Taro.showToast({
      title: text,
      icon: success ? 'success' : 'none',
      duration: duration
    }).then(r => {
    });
  }


  static showSingleModel(title: string = '提示', content: string, callback?: ModalCallback) {
    Taro.showModal({
      title: title,
      content: content,
      showCancel: false,
      success: function (modalRes) {
        if (modalRes.confirm) {
          // 用户点击确定后，再执行后续操作
          callback && callback(true);
        }
      }
    }).then(r => {
    });
  }


  static modal(
    title: string = '提示',
    content: string,
    showCancel: boolean,
    callback?: ModalCallback,
    confirmColor: string = "#5677fc",
    confirmText: string = "确定"
  ): void {
    Taro.showModal({
      title: title,
      content: content,
      showCancel: showCancel,
      cancelColor: "#555",
      confirmColor: confirmColor,
      confirmText: confirmText,
      success(res) {
        if (res.confirm) {
          callback && callback(true);
        } else {
          callback && callback(false);
        }
      }
    }).then(r => {
    });
  }

  static isEmpty(collection: any[] | undefined) {
    return !collection || collection.length === 0;
  }

  static getDefaultArray(collection: any[] | undefined): any[] {
    return Utils.isEmpty(collection) ? [] : collection as any[];
  }


  static getUrlWithObject(url: string, params: any): string {
    if (!params) {
      return url;
    }
    const queryString = encodeURIComponent(JsonUtils.stringify(params))
    return `${url}?data=${queryString}`;
  }

  static getObjectWithUrl<T>(params: any): T {
    const dataString = decodeURIComponent(params);
    return JsonUtils.parse<T>(dataString);
  }

  //判断字符串不为空，并且大于0
  static isThanZero(value: string | number | null | undefined): boolean {
    if (value === null || typeof value === 'undefined') {
      return false;
    }

    let stringValue: string;
    if (typeof value === 'number') {
      // 如果是数字，可以直接比较，或者转换为字符串进行统一处理
      // return value > 0; // 如果是数字，这是最直接的
      stringValue = String(value); // 为了与字符串情况统一 parseFloat 逻辑
    } else { // value is string
      stringValue = value;
    }
    if (stringValue.trim() === '') {
      return false;
    }
    const numericValue = parseFloat(stringValue);
    return !Number.isNaN(numericValue) && numericValue > 0;
  }


  static getChannel(instance) {
    if (instance.page && instance.page.getOpenerEventChannel) {
      const openerEventChannel = instance.page.getOpenerEventChannel();
      if (openerEventChannel) {
        return openerEventChannel as Taro.EventChannel;
      }
      return null
    }
  }

  static getI(): getCurrentInstance.Current {
    return Taro.getCurrentInstance();
  }

  static normalizeInitialValues(params: Record<string, any>, config: any[]): DynamicFormData {
    const normalizedValues: DynamicFormData = {};

    // 1. 创建一个从字段名到类型的快速查找表，提高效率
    const fieldTypeMap = new Map<string, string>();
    config.forEach(item => {
      if (item.fields && item.type) {
        fieldTypeMap.set(item.fields, item.type);
      }
    });

    // 2. 遍历所有从 URL 接收到的参数
    for (const key in params) {
      if (Object.prototype.hasOwnProperty.call(params, key)) {
        const rawValue = params[key];
        const fieldType = fieldTypeMap.get(key); // 从查找表中获取该字段的类型

        // 3. 根据字段类型进行不同的处理
        switch (fieldType) {
          case 'checkbox':
            // 如果是 checkbox 类型，我们知道它的值应该是数组
            // 尝试将其从 JSON 字符串解析回数组
            try {
              if (typeof rawValue === 'string') {
                normalizedValues[key] = JSON.parse(rawValue);
              } else {
                normalizedValues[key] = rawValue; // 如果已经是数组，直接用
              }
            } catch (e) {
              console.warn(`解析 checkbox 参数 '${key}' 失败，值:`, rawValue);
              normalizedValues[key] = []; // 解析失败则给一个空数组
            }
            break;

          case 'inputNumber':
            // 如果是数字输入框，将其转换为数字
            normalizedValues[key] = Number(rawValue);
            break;

          default:
            // 对于所有其他类型 (input, radio, textarea 等)，直接赋值
            normalizedValues[key] = rawValue;
            break;
        }
      }
    }

    return normalizedValues;
  };


  static getParamsByRouter(instance: getCurrentInstance.Current) {
    if (instance && instance.router && instance.router.params) {
      return instance.router.params;
    }
    return null;
  }


  static emit(i: (Taro.EventChannel | null | undefined), key, value) {
    if (i && typeof i.emit === 'function') {
      try {
        // 尝试调用 emit 方法
        i.emit(key, value);
      } catch (error) {
        // 捕获并记录调用过程中的错误
      }
    } else {
      // 记录无效事件通道的错误信息
    }
  }

  static payWx(params: PayParamsModel, onSuccess?: (res: any) => void) {
    const op: requestPayment.Option = {
      nonceStr: params.nonceStr,
      package: params.package,
      paySign: params.paySign,
      timeStamp: params.timeStamp,
      signType: "MD5",
      success: (res) => {
        if (onSuccess) {
          onSuccess(res); // 调用传入的成功回调
        }
      },
      fail: (res) => {
        console.log(res)
      },
      complete: (res) => {
        console.log(res)
      }
    }
    Taro.requestPayment(op)
  }


  static transformApiDataToFormConfig(apiData: MoreOptions[], disabled: boolean = true): FormConfig[] {
    if (!Array.isArray(apiData)) {
      return [];
    }

    return apiData.map((question) => {
      // 1. 创建一个基础的表单项配置
      const formItem: FormConfig = {
        // 使用 'question_' + id 作为唯一的字段名，避免冲突
        name: `${LocalData.FIlED_START}${question.id}`,
        fields: `${LocalData.FIlED_START}${question.id}`,
        label: question.name,
        layout: 'vertical',
        disabled: disabled,
        placeholder: `请输入${question.name}`,
        required: true, // 假设所有问题都是必填的，您可以根据 API 调整
        type: '', // 类型将在下面决定
      };
      const defaultProps = {direction: 'horizontal'};
      // 2. 根据 API 返回的 type 决定表单项的类型
      switch (question.type) {
        case 0: // 0 代表单选
          formItem.type = 'radio';
          formItem.className = 'custom-radio-group';
          formItem.props = {
            ...defaultProps,
          };
          break;
        case 1: // 1 代表多选
          formItem.type = 'checkbox';
          formItem.className = 'hobby-checkbox-group';
          formItem.props = {
            ...defaultProps,
          };
          break;
        case 2: // 1 代表多选
          formItem.type = 'input';
          formItem.className = 'hobby-checkbox-group';
          formItem.props = {
            ...defaultProps,
          };
          break;
        default: // 其他类型，如果没有子选项，我们默认为一个文本输入框
          if (!question.children || question.children.length === 0) {
            formItem.type = 'textarea';
            formItem.placeholder = `请输入“${question.name}”`;
          } else {
            // 如果有子选项但 type 未知，可以给一个默认或跳过
            formItem.type = 'radio';
          }
          break;
      }
      // 3. 如果有子选项，将它们转换为 options 数组
      if (question.children && question.children.length > 0) {
        formItem.options = question.children.map((option) => ({
          // 将 API 的 name 映射到 options 的 label
          label: option.name,
          name: option.name,
          value: String(option.id), // 确保 value 是字符串或数字
        }));
      }
      return formItem;
    });
  }


  static scanFile(url) {
    const path = LocalUtils.getLocalStr(url)
    if (Utils.isNotBlank(path)) {
      Utils.openFile(path)
    } else {
      Utils.showLoading("正在下载")
      Utils.downloadFile(url)
    }
  }

  private static openFile(filePath) {
    const fileType = Utils.getFileType(filePath)
    if (fileType === LocalData.UNKNOWN_FILE_TYPE_SWITCH) {
      Taro.previewImage({
        current: '',
        urls: [filePath],
        success: function (res2) {
          //toast

        }
      });
    } else {
      Taro.openDocument({
        filePath: filePath,
        showMenu: true,
        success: function (res2) {
          //toast

        }
      })
    }
  }


  private static downloadFile(url) {
    Taro.downloadFile({
      url: url,//服务器上的pdf地址
      success: function (res) {
        Taro.hideLoading()
        LocalUtils.setLocalStr(url, res.tempFilePath)
        Utils.openFile(res.tempFilePath)
      }
    })
  }

  //
  private static getFileType(filePath: string | null | undefined): string {
    if (!filePath || filePath.trim() === '') {
      return LocalData.UNKNOWN_FILE_TYPE_SWITCH;
    }
    const lastDotIndex = filePath.lastIndexOf('.');
    if (lastDotIndex === -1 || lastDotIndex === 0 || lastDotIndex === filePath.length - 1) {
      return LocalData.UNKNOWN_FILE_TYPE_SWITCH;
    }
    const extension = filePath.substring(lastDotIndex + 1).toLowerCase();
    switch (extension) {
      case 'doc':
      case 'docx':
      case 'xls':
      case 'xlsx':
      case 'ppt':
      case 'pptx':
      case 'pdf':
        return extension; // 直接返回匹配到的扩展名
      // case 'jpeg': // 如果想将 jpeg 归类为 jpg
      //   return 'jpg';
      default:
        return LocalData.UNKNOWN_FILE_TYPE_SWITCH;
    }
  }

  static updateManager() {
    try {
      const updateManager = Taro.getUpdateManager()
      updateManager.onCheckForUpdate(function (res) {
        // 请求完新版本信息的回调
        if (res.hasUpdate) {
          Utils.showToast({title: '发现新版本，正在下载...', icon: 'none'});
        }
      })
      updateManager.onUpdateReady(function () {
        Taro.showModal({
          title: '更新提示',
          content: '新版本已经准备好，是否重启应用？',
          success: function (res) {
            if (res.confirm) {
              updateManager.applyUpdate()
            }
          }
        })
      })
      updateManager.onUpdateFailed(function () {
        // 新的版本下载失败
        Utils.showToast({title: '新版本下载失败，请检查网络后重试', icon: 'none'});
      })
    } catch (e) {
      LogUtils.info("error-updateManager")
    }
  }

  static isMobilePhone(phone: string): boolean {
    // 使用正则表达式验证手机号格式，适用于中国大陆手机号
    if (!phone) return false;
    const reg = /^1[3-9]\d{9}$/;
    return reg.test(phone);
  }

  // 验证邮箱格式
  static isEmail(email: string): boolean {
    if (!email) return false;
    const reg = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
    return reg.test(email);
  }


  static getQuery(params) {
    const paramsDataString = JsonUtils.stringify(params);
    const encodedData = encodeURIComponent(paramsDataString);
    return `data=${encodedData}`
  }

  static buildUrlFromLaunchOptions(options?: Taro.getLaunchOptionsSync.LaunchOptions): string {
    if (!options || !options.path) {
      return '';
    }
    let url = options.path;
    const query = options.query;
    if (query && Object.keys(query).length > 0) {
      const filteredQuery = {};
      for (const [key, value] of Object.entries(query)) {
        // 过滤掉 stamp 参数
        if (key === 'stamp') {
          continue;
        }
        // 对参数值进行解码
        filteredQuery[key] = decodeURIComponent(String(value));
      }
      const queryString = Object.entries(filteredQuery)
        .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
        .join('&');
      url += `?${queryString}`;
    }
    return url;
  }

  static goEditProfile() {
    if (!LocalUtils.isLogin()) {
      Utils.reLaunch({
        url: RouthPath.login,
      }, 4)
      LogUtils.info("go->login")
      return
    }
    if (!LocalUtils.getMobile()) {
      Utils.switchTab({
        url: LocalData.currentIndex === 0 ? RouthPath.tabbarHome : RouthPath.tabProject
      })
      setTimeout(() => {
        Utils.modal("完善用户信息", "请完善用户信息后再使用该功能", true, (ok) => {
          if (ok) {
            Utils.navigateTo({
              url: RouthPath.editProfilePage,
            })
          }
        })
      }, 100); // 延迟100毫秒
    }
  }


  static getTopHeight() {
    const systemInfo = Taro.getSystemInfoSync();
    const menuButtonInfo = Taro.getMenuButtonBoundingClientRect();
    const statusBarHeight = systemInfo.statusBarHeight || 0;
    const navBarContentHeight = (menuButtonInfo.top - statusBarHeight) * 2 + menuButtonInfo.height;
    // 总高度 = 状态栏 + 导航栏 + 搜索框区域高度(估算值，根据实际情况调整)
    return statusBarHeight + navBarContentHeight;
  }

  static isEmptyJsonObject(jsonString: string | undefined): boolean {
    // 修改：仅对 undefined/null 返回 true，空字符串继续解析（会触发 JSON.parse 错误）
    if (jsonString == null) return true;
    try {
      // 解析JSON字符串
      const parsedObj = JSON.parse(jsonString);
      // 检查是否为纯对象（排除null、数组、其他类型）且无自有属性
      return (
        typeof parsedObj === 'object' &&
        parsedObj !== null &&
        !Array.isArray(parsedObj) &&
        Object.keys(parsedObj).length === 0
      );
    } catch (error) {
      // JSON解析失败时，返回 false（非空对象）
      return false;
    }
  }


}


